//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package user_dao

import (
	"context"
	"fmt"

	"atomgit.com/openlinksaas/api-server/dao/db_ns"
	"atomgit.com/openlinksaas/proto-gen-go.git/user_notice_api"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type AddToProjectFromOrgDataDbItem struct {
	ProjectId string `bson:"projectId"`
	OrgId     string `bson:"orgId"`
}

func GetIdForAddToProjectFromOrgData(projectId string) string {
	return "AddToProjectFromOrg:" + projectId
}

type UserNoticeInfoDbItem struct {
	UserNoticeId            string                         `bson:"_id"` //自动生成
	UserId                  string                         `bson:"userId"`
	NoticeFromId            string                         `bson:"noticeFromId"`
	TimeStamp               int64                          `bson:"timeStamp"`
	HasRead                 bool                           `bson:"hasRead"`
	SendUserId              string                         `bson:"sendUserId"`
	AddToProjectFromOrgData *AddToProjectFromOrgDataDbItem `bson:"addToProjectFromOrgData"`
}

func (item *UserNoticeInfoDbItem) ToUserNoticeInfo() *user_notice_api.UserNoticeInfo {
	info := &user_notice_api.UserNoticeInfo{
		NoticeFromId: item.NoticeFromId,
		TimeStamp:    item.TimeStamp,
		HasRead:      item.HasRead,
		SendUserId:   item.SendUserId,
	}
	if item.AddToProjectFromOrgData != nil {
		info.NoticeData = &user_notice_api.UserNoticeInfo_AddToProjectFromOrgData{
			AddToProjectFromOrgData: &user_notice_api.AddToProjectFromOrgData{
				OrgId:     item.AddToProjectFromOrgData.OrgId,
				ProjectId: item.AddToProjectFromOrgData.ProjectId,
			},
		}
	}
	return info
}

type _UserNoticeDao struct {
	mc *mongo.Collection
}

func newUserNoticeDao(db *mongo.Database) (*_UserNoticeDao, error) {
	mc := db.Collection(db_ns.DB_NS_USER + "notice")
	_, err := mc.Indexes().CreateOne(context.Background(), mongo.IndexModel{
		Keys: bson.D{{"userId", 1}, {"timeStamp", 1}},
	})
	if err != nil {
		return nil, err
	}
	return &_UserNoticeDao{mc: mc}, nil
}

func (db *_UserNoticeDao) Insert(ctx context.Context, dbItem *UserNoticeInfoDbItem) error {
	dbItem.UserNoticeId = db.genUserNoticeId(dbItem.UserId, dbItem.NoticeFromId)
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_UserNoticeDao) genUserNoticeId(userId, noticeFromId string) string {
	return fmt.Sprintf("%s:%s", userId, noticeFromId)
}

func (db *_UserNoticeDao) Exist(ctx context.Context, userId, noticeFromId string) (bool, error) {
	userNoticeId := db.genUserNoticeId(userId, noticeFromId)
	count, err := db.mc.CountDocuments(ctx, bson.M{"_id": userNoticeId, "userId": userId})
	return count > 0, err
}

func (db *_UserNoticeDao) Get(ctx context.Context, userId, noticeFromId string) (*UserNoticeInfoDbItem, error) {
	userNoticeId := db.genUserNoticeId(userId, noticeFromId)
	retItem := &UserNoticeInfoDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"_id": userNoticeId, "userId": userId}).Decode(retItem)
	return retItem, err
}

func (db *_UserNoticeDao) Remove(ctx context.Context, userId, noticeFromId string) error {
	userNoticeId := db.genUserNoticeId(userId, noticeFromId)
	_, err := db.mc.DeleteOne(ctx, bson.M{"_id": userNoticeId, "userId": userId})
	return err
}

func (db *_UserNoticeDao) Count(ctx context.Context, userId string, filterByHasRead, hasRead bool) (uint32, error) {
	query := bson.M{"userId": userId}
	if filterByHasRead {
		query["hasRead"] = hasRead
	}
	count, err := db.mc.CountDocuments(ctx, query)
	return uint32(count), err
}

func (db *_UserNoticeDao) List(ctx context.Context, userId string, filterByHasRead, hasRead bool, offset, limit int64) ([]*UserNoticeInfoDbItem, error) {
	if limit <= 0 {
		return []*UserNoticeInfoDbItem{}, nil
	}
	query := bson.M{"userId": userId}
	if filterByHasRead {
		query["hasRead"] = hasRead
	}

	cursor, err := db.mc.Find(ctx, query, options.Find().SetSkip(offset).SetLimit(limit).SetSort(bson.M{"timeStamp": -1}))
	if err != nil {
		return nil, err
	}
	retList := []*UserNoticeInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_UserNoticeDao) SetHasRead(ctx context.Context, userId, noticeFromId string) error {
	userNoticeId := db.genUserNoticeId(userId, noticeFromId)
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": userNoticeId, "userId": userId}, bson.M{"$set": bson.M{"hasRead": true}})
	return err
}
